package com.ce.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;



public class WebAppMonitor extends Thread {
	
	/** 连接超时时间，默认为10秒*/
	private int connectTimeout=10;
	
	/** 读取数据超时时间，默认为30秒*/
	private int readTimeout=30;
	
	/** 服务器状态监视周期，默认为30秒*/
	private int interval=30;

	/** 日志文件最大值，默认为100M*/
	private int maxLogSize=100;

	/** 控制台中日志的最大行数，默认为500行*/
	private int maxLogRow=500;
	
	/** 返回错误的最大容忍次数，默认为3次。即连续3次返回错误信息时重启服务 */
	private int maxTestNum = 3;

	private String testUrl;
	private String result;
	private String command;
	private int curTestNum = 0;
	/**
	 * 开发人：andy
	 * 开发日期: 2013-10-26  下午07:36:10
	 * 功能描述: 
	 * 方法的参数和返回值: 
	 * @param args
	 * @throws IOException 
	 * @throws MalformedURLException 
	 */
	public static void main(String[] args) throws MalformedURLException, IOException {
//		Runtime r = Runtime.getRuntime();
//		System.out.println(r.totalMemory()-r.freeMemory());
//		System.out.println(r.maxMemory());
//		System.out.println(r.freeMemory());
		WebAppMonitor sm = new WebAppMonitor();
//		System.out.println(sm.getTestInfo("http://localhost:81/mis/check.jsp?ssoid=89c9ab621da74c4480b859da56dfed7b"));
//		JFrame jf = sm.getJFrame();
//		jf.setVisible(true);
//		sm.start();
		sm.run();
	}
	
	public WebAppMonitor(){
		init();
	}

	private void init(){
		Properties p = new Properties();
		File f = new File("../conf/config.ini");
		String path = f.getAbsolutePath();
		try {
			path = f.getCanonicalPath();
		} catch (IOException e1) {
		}
		printLog("正在读取配置文件["+ path +"]");
		try {
			p.load(new FileInputStream(f));
		} catch (FileNotFoundException e) {
			printLog("系统找不到配置文件["+ path +"]，使用默认配置！");
		} catch (IOException e) {
			printLog("文件["+ f.getAbsolutePath() +"]读取失败!");
		}
		testUrl = p.getProperty("testUrl", "http://localhost:81/mis/test.jsp");
		result = p.getProperty("result","ok");
		command = p.getProperty("command","restart.bat");
		interval = getIntValue(p,"interval",interval);
		maxTestNum  = getIntValue(p,"maxTestNum",maxTestNum);
		connectTimeout = getIntValue(p,"connectTimeout",connectTimeout);
		readTimeout = getIntValue(p,"readTimeout",readTimeout);
		maxLogSize = getIntValue(p,"maxLogSize",maxLogSize);
		maxLogRow = getIntValue(p,"maxLogRow",maxLogRow);
		printLog("配置信息加载完毕\ntestUrl="+testUrl+"\nresult="+result+"\ncommand="+command+"\ninterval="+interval+
				"\nconnectTimeout="+connectTimeout+"\nreadTimeout="+readTimeout+"\nmaxLogSize="+maxLogSize);
	}

	@Override
	public void run() {
		printLog("开始对服务器进行监控...");
		while(true){
			try {
				String line = getTestInfo(testUrl);
				String[] res = line.split("  ");
				if(result.equals(res[0])){
					printLog("["+res[0]+"]==["+result+"]√"+line.replace(result, ""));
					curTestNum = 0;
				}
				else{
					throw new Exception("从服务器返回信息["+line+"]与期望的返回值["+result+"]不匹配");
				}
			} catch (Exception e) {
				if(e.getMessage()!=null&&e.getMessage().length()>0){
					printLog("错误消息:["+e.getClass().getName()+"]"+e.getMessage());
				}
				if(++curTestNum>=maxTestNum){
					printLog("连续"+curTestNum+"次从服务器返回错误消息，将重启服务...");
					curTestNum = 0;
					restartService(command);
				}
			}
			try {
				if(new File("log.txt").length()>maxLogSize*1024*1024){
					out.close();
					out = null;
				}
				Thread.sleep(interval*1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	* 开发人：andy
	* 开发日期: 2013-10-27  上午10:42:53
	* 功能描述: 获取配置文件中的数字值
	* 方法的参数和返回值: 
	* @param p
	* @param pName
	* @param defaultValue
	* @return
	*/
	private int getIntValue(Properties p,String pName,int defaultValue) {
		try {
			return Integer.parseInt(p.getProperty(pName,""+defaultValue));
		} catch (NumberFormatException e1) {
			printLog("["+defaultValue+"]参数设置不正确，将使用默认配置:"+defaultValue+"");
		}
		return defaultValue;
	}

	private static String sessionid="";
	/**
	* 开发人：andy
	* 开发日期: 2013-10-27  上午08:05:03
	* 功能描述: 获取服务心跳信息
	* 方法的参数和返回值: 
	* @param testUrl
	* @return
	* @throws MalformedURLException
	* @throws IOException
	*/
	private String getTestInfo(String testUrl) throws MalformedURLException, IOException {
		URL url = new java.net.URL(testUrl);
		HttpURLConnection con = (HttpURLConnection)url.openConnection(); 
		con.setRequestProperty("User-Agent","Mozilla/4.0");
		con.setRequestProperty("Cookie", sessionid);
//		con.setConnectTimeout(connectTimeout*1000);
//		con.setReadTimeout(readTimeout*1000);
		InputStream in = con.getInputStream();
		BufferedReader reader = new BufferedReader(new InputStreamReader(in));
		String line = null;
		StringBuffer buff = new StringBuffer();
		while((line = reader.readLine())!=null){
			buff.append(line+"\n");
		}
		reader.close();
		String sid = con.getHeaderField("Set-Cookie");
		if(sid!=null){
			sid = sid.split(";")[0];
		}
		if(sid!=null&&!sessionid.equals(sid)){
			sessionid = sid;
		}
		con.disconnect();
		return buff.toString().trim();
	}

	/**
	* 开发人：andy
	* 开发日期: 2013-10-27  上午08:04:14
	* 功能描述: 调用命令，重启服务
	* 方法的参数和返回值: 
	* @param command
	*/
	private void restartService(final String command) {
		new Thread(){
			public void run() {
				try {
					printLog("开始调用命令["+command+"]");
					Process pro = Runtime.getRuntime().exec(command);
					BufferedReader in = new BufferedReader(new InputStreamReader(pro.getInputStream()));
					String tmp = in.readLine();
					while(tmp!=null){
						printLog("[CMD]"+tmp);
						tmp = in.readLine();
					}
					in.close();
					pro.destroy();
				} catch (IOException e1) {
					printLog("调用命令["+command+"]失败!");
					if(e1.getMessage()!=null&&e1.getMessage().length()>0){
						printLog("错误消息:"+e1.getMessage());
					}
				}
			}
		}.start();
	}
	private PrintWriter out;
	private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	/**
	* 开发人：andy
	* 开发日期: 2013-10-27  上午08:05:28
	* 功能描述: 记录日志信息
	* 方法的参数和返回值: 
	* @param info
	*/
	private void printLog(String info){
		if(out==null){
			try {
				File f = new File("../logs/log.txt");
				File dir = f.getParentFile();
				if(!dir.exists())dir.mkdirs();
				if(f.length()>maxLogSize*1024*1024){//当日志文件大于100M时，转存文件
					String fn = "log"+new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
					f.renameTo(new File(fn+".txt"));
					ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(fn+".zip"));
					zout.putNextEntry(new ZipEntry(fn+".txt"));
					FileInputStream in = new FileInputStream(fn+".txt");
					byte[] buff = new byte[8192];
					int len = in.read(buff);
					while(len>0){
						zout.write(buff,0,len);
						len = in.read(buff);
					}
					in.close();
					zout.closeEntry();
					zout.close();
					new File(fn+".txt").delete();
				}
				out = new PrintWriter(new FileWriter(f,true));
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		info = sdf.format(new Date())+" "+info;
		out.println(info);
		out.flush();
		System.out.println(info);
	}
	
}
